package com.onpositive.dataminer.core;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;

import com.onpositive.semantic.model.api.changes.HashDelta;
import com.onpositive.semantic.model.api.changes.ISetDelta;
import com.onpositive.semantic.model.api.realm.AbstractRealm;
import com.onpositive.semantic.model.api.realm.IRealm;
import com.onpositive.semantic.model.api.realm.IRealmChangeListener;

public class CountingCompositeRealm<T> extends AbstractRealm<T> implements
		IRealmChangeListener<T> {

	protected HashMap<T, Integer> mz = new HashMap<T, Integer>();
	protected LinkedHashSet<IRealm<T>> realms = new LinkedHashSet<IRealm<T>>();

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void addRealm(IRealm<T> r) {
		Collection<T> contents = r.getContents();		
		r.addRealmChangeListener(this);
		realmChanged(r,(HashDelta)HashDelta.buildAdd(contents));
	}

	protected synchronized boolean add(T o) {
		Integer remove = mz.get(o);
		boolean rm = false;
		if (remove == null) {
			remove = 0;
			rm = true;
		}
		remove = remove + 1;
		mz.put(o, remove);		
		return rm;
	}

	protected synchronized boolean remove(T o) {
		Integer remove = mz.get(o);
		boolean rm = false;
		if (remove != null) {
			remove = remove - 1;
			if (remove == 0) {
				mz.remove(o);
				rm = true;
			}
		}
		return rm;
	}

	@SuppressWarnings("unchecked")
	public void removeRealm(IRealm<T> r) {
		Collection<T> contents = r.getContents();
		r.removeRealmChangeListener(this);
		realmChanged(r, (HashDelta) HashDelta.buildRemove(contents));
	}

	@Override
	public Collection<T> getContents() {
		return mz.keySet();
	}

	@Override
	public IRealm<T> getParent() {
		return null;
	}

	@Override
	public int size() {
		return mz.size();
	}

	@Override
	public boolean isOrdered() {
		return false;
	}

	@Override
	public boolean mayHaveDublicates() {
		return false;
	}

	@Override
	public boolean contains(Object o) {
		return mz.containsKey(o);
	}

	@Override
	public Iterator<T> iterator() {
		return mz.keySet().iterator();
	}

	@Override
	public synchronized void realmChanged(IRealm<T> realmn, ISetDelta<T> delta) {
		HashDelta<T> m = new HashDelta<T>();
		for (Object o : delta.getAddedElements()) {
			boolean add = add((T) o);
			if (add) {
				m.markAdded((T) o);
			}
		}
		for (Object o : delta.getRemovedElements()) {
			boolean add = remove((T) o);
			if (add) {
				m.markRemoved((T) o);
			}
		}
		for (Object o : delta.getChangedElements()) {
			m.markChanged((T) o);
		}
		fireDelta(m);
	}
}
